import WebSocket from "./websocket";
import uuid from "uuid/v4";
import { EventEmitter } from 'events';

interface Message {
    type: string;
    callbackId?: string;
    [key: string]: any;
}

export default class Socket extends WebSocket {
    // 登录校验值
    public id: string = "";
    public callbackEvent = new EventEmitter();
    public receiveQueue: { [type: string]: Message[] } = {};

    constructor(url: string) {
        super(url);
        this.socketEmitter.on("close", () => {
            this.id = "";
        });
    }

    /**
     * 登录
     * @param username 用户名
     * @param password md5后的密码
     */
    public async login(username: string, password: string, rember: boolean) {
        const res = await this.wsSync({ type: "login", username, password });
        this.id = res.id;
        if (res.id && rember) {
            localStorage.setItem("rember", rember.toString());
            localStorage.setItem("login", JSON.stringify({
                username,
                password,
            }));
        }
        return res.number;
    }

    public onMessage(event: MessageEvent) {
        try {
            const data = JSON.parse(event.data);
            if (data.callbackId) {
                this.callbackEvent.emit(data.callbackId, data.result);
            } else if (this.emitter.rawListeners(data.type).length > 0) {
                this.emitter.emit(data.type, data);
            } else {
                if (!this.receiveQueue[data.type]) {
                    this.receiveQueue[data.type] = [];
                }
                this.receiveQueue[data.type].push(data);
            }
        } catch (error) {
            console.error(error);
        }
    }

    public wsCallback(message: Message, callback: (message: any) => void) {
        message.callbackId = uuid();
        this.callbackEvent.once(message.callbackId, callback);
        this.send(message);
    }

    public async wsSync(message: Message): Promise<any> {
        return new Promise((resolve) => {
            message.callbackId = uuid();
            this.callbackEvent.once(message.callbackId, (response) => {
                resolve(response);
            });
            this.send(message);
        });
    }

    public send(message: Message) {
        message.id = this.id;
        super.send(message);
    }

    public on(eventName: string, callback: (data: Message) => void) {
        super.on(eventName, callback);
        if (this.receiveQueue[eventName]) {
            while (this.receiveQueue[eventName].length !== 0) {
                const data = this.receiveQueue[eventName].shift();
                if (data) {
                    this.emitter.emit(data.type, data);
                }
            }
        }
    }
}